/*
g++ testopencv.cpp -lcv
g++ testopencv.cpp -lopencv_highgui -lopencv_imgproc -lopencv_imgcodecs -lopencv_videoio -lopencv_core
 Usage： <cmd> <file_in> <file_out>
 */

#include <opencv2/opencv.hpp>
#include <iostream>

// 色域转换
int test_color_convert(int, char *argv[])
{
    // 读取原始图像
    auto in_image = cv::imread(argv[1], cv::IMREAD_UNCHANGED);
    if (in_image.empty())
    {
        std::cout << "Error! Input image cannot be read..." << std::endl;
        return -1;
    }

    // 创建两个具有图像名称的窗口
    cv::namedWindow(argv[1], cv::WINDOW_AUTOSIZE);
    cv::namedWindow(argv[2], cv::WINDOW_AUTOSIZE);

    // 在之前创建的窗口中显示图片
    cv::imshow(argv[1], in_image);

    // 转换色域
    cv::Mat out_image;
    cv::cvtColor(in_image, out_image, cv::COLOR_RGB2GRAY);

    // 显示新图像
    cv::imshow(argv[2], out_image);

    std::cout << "Press any key to exit..." << std::endl;
    cv::waitKey();

    // 写入图像
    cv::imwrite(argv[2], out_image);

    return 0;
}

// 格式转换
int test_pic_format(int, char *argv[])
{
    // 读入图片
    auto M = cv::imread(argv[1], cv::IMREAD_COLOR);

    // 判断文件是否正常打开
    if (M.empty())
    {
        fprintf(stderr, "Can not load image %s\n", argv[1]);

        // 等待6000 ms后窗口自动关闭
        cv::waitKey(6000);
        return -1;
    }

    // 显示图片
    cv::imshow("image", M);
    cv::waitKey();

    // 存为bmp格式图片
    cv::imwrite(cv::String(argv[2]) + ".bmp", M);
    return 0;
}

#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>

int test_video_capture(int argc, char **argv)
{
    // 创建窗口
    cv::namedWindow("Example3", cv::WINDOW_AUTOSIZE);

    cv::VideoCapture capture(argv[1]);

    // 循环读取帧并显示
    cv::Mat frame;
    for (;;)
    {
        capture >> frame;
        if (frame.empty())
            break;

        cv::imshow("Example3", frame);

        // 30毫秒内按键退出
        if ((char)cv::waitKey(30) >= 0)
            break;
    }

    return 0;
}

int g_slider_position = 0;
int g_run = 1, g_dontset = 0;
cv::VideoCapture g_cap;

// 设置帧位置
void onTrackbarSlide(int pos, void *)
{
    g_cap.set(cv::CAP_PROP_POS_FRAMES, pos);

    if (!g_dontset)
        g_run = 1;

    g_dontset = 0;
}

int test_video_position(int argc, char **argv)
{
    cv::namedWindow("Example2_4", cv::WINDOW_AUTOSIZE);

    g_cap.open(std::string(argv[1]));

    // 获取帧数和宽高
    int frames = (int)g_cap.get(cv::CAP_PROP_FRAME_COUNT);
    int tmpw = (int)g_cap.get(cv::CAP_PROP_FRAME_WIDTH);
    int tmph = (int)g_cap.get(cv::CAP_PROP_FRAME_HEIGHT);
    std::cout << "Video has " << frames << " frames of dimensions(" << tmpw << ", " << tmph << ")." << std::endl;

    // 创建跟踪条
    cv::createTrackbar("Position", "Example2_4", &g_slider_position, frames, onTrackbarSlide);

    cv::Mat frame;
    for (;;)
    {
        if (g_run != 0)
        {
            // 读取帧
            g_cap >> frame;
            if (frame.empty())
                break;

            int current_pos = (int)g_cap.get(cv::CAP_PROP_POS_FRAMES);
            g_dontset = 1;

            cv::setTrackbarPos("Position", "Example2_4", current_pos);

            // 显示帧
            cv::imshow("Example2_4", frame);

            g_run -= 1;
        }

        // 处理按键
        char c = (char)cv::waitKey(10);
        if (c == 's')
        {
            g_run = 1;
            std::cout << "Single step, run = " << g_run << std::endl;
        }
        if (c == 'r')
        {
            g_run = -1;
            std::cout << "Run mode, run = " << g_run << std::endl;
        }
        if (c == 27)
            break;
    }

    return 0;
}

// 高斯（过滤器）模糊（平滑）
void test_pic_gaussionblur(int argc, char *argv[])
{
    cv::namedWindow("Example2_5 - in", cv::WINDOW_AUTOSIZE);
    cv::namedWindow("Example2_5 - out", cv::WINDOW_AUTOSIZE);

    // 读取并显示图片
    cv::Mat image = cv::imread(argv[1]);
    cv::imshow("Example2_5 - in", image);

    // 处理图片
    cv::Mat out;
    cv::GaussianBlur(image, out, cv::Size(5, 5), 3, 3);
    cv::GaussianBlur(out, out, cv::Size(5, 5), 3, 3);

    // 显示图片
    cv::imshow("Example2_5 - out", out);

    cv::waitKey(0);
}

// 视频图像极化
int test_video_polar(int argc, char *argv[])
{
    cv::namedWindow("Example2_11", cv::WINDOW_AUTOSIZE);
    cv::namedWindow("Log_Polar", cv::WINDOW_AUTOSIZE);

    cv::VideoCapture capture(argv[1]);

    // 获取画面属性
    double fps = capture.get(cv::CAP_PROP_FPS);
    cv::Size size((int)capture.get(cv::CAP_PROP_FRAME_WIDTH), (int)capture.get(cv::CAP_PROP_FRAME_HEIGHT));

    // 创建视频输出对象
    cv::VideoWriter writer(argv[2], CV_FOURCC('M', 'J', 'P', 'G'), fps, size);

    cv::Mat logpolar_frame, bgr_frame;
    for (;;)
    {
        // 读取帧
        capture >> bgr_frame;
        if (bgr_frame.empty())
            break;

        // 处理帧
        cv::logPolar(bgr_frame, logpolar_frame, cv::Point2f(bgr_frame.cols / 2, bgr_frame.rows / 2), 200, cv::WARP_FILL_OUTLIERS);

        // 显示新帧
        cv::imshow("Log_Polar", logpolar_frame);

        // 输出新帧
        writer << logpolar_frame;

        // 处理按键
        char c = cv::waitKey(10);
        if (c == 27)
            break;
    }

    capture.release();
    return 0;
}

int main(int argc, char *argv[])
{
    //./a.out ../../res/lena.png ../../res/lena1.png
    test_color_convert(argc, argv);

    //./a.out ../../res/lena.png ../../res/lena2.png
    // test_pic_format(argc, argv);

    // ./a.out /home/ljd/Videos/跑步机遛猫.mp4
    // test_video_capture(argc, argv);

    // ./a.out /home/ljd/Videos/跑步机遛猫.mp4
    // test_video_position(argc, argv);

    //./a.out ../../res/lena.png
    // test_pic_gaussionblur(argc, argv);

    // ./a.out /home/ljd/Videos/跑步机遛猫.mp4 /home/ljd/Downloads/aaa.mp4
    // test_video_polar(argc, argv);

    return 0;
}